import { List } from 'linqts';

export interface Node {
    Id: number;
    x: number;
    y: number;
    z: number;
}

export interface Elem {
    Id: number;
    NodeIds: List<number>;
}

export interface Group {
    GroupId: number;
    ItemIds: List<number>;
}

export interface GroupName {
    GroupId: number;
    GroupName: string;
}

export interface FemMesh {
    NodeList: List<Node>;
    Elem3DList: List<Elem>;
    Elem2DList: List<Elem>;
    Elem1DList: List<Elem>;

    NodeGroups: List<Group>;
    ElemGroups: List<Group>;

    Elem3DGroups: List<Group>;
    Elem2DGroups: List<Group>;
    Elem1DGroups: List<Group>;

    NodeGroupNames: List<GroupName>;
    ElemGroupNames: List<GroupName>;
}

//
// check if an elem exist in list with binary search algorithm
//
export function IsElemExist(elemList: List<Elem>, elemId: number): boolean {
    let found = false;
    const arr = elemList.ToArray();
    let start = 0;
    let end = arr.length - 1;
    let mid = start;
    while (true) {
        if (start > end) {
            break;
        }

        mid = Math.floor((start + end) / 2);
        const id = arr[mid].Id;
        if (elemId === id) {
            found = true;
            break;
        } else if (elemId < id) {
            end = mid - 1;
        } else {
            start = mid + 1;
        }
    }
    return found;
}

//
// get node with specificated id, with binary search algorithm
//
export function GetNode(nodeList: List<Node>, nodeId: number): Node {
    return GetItem<Node>(nodeList, nodeId, node => node.Id);
}

//
// get elem with specificated id, with binary search algorithm
//
export function GetElem(elemList: List<Elem>, elemId: number): Elem {
    return GetItem<Elem>(elemList, elemId, elem => elem.Id);
}

//
// get groupName object with specificated id, with binary search algorithm
//
export function GetGroupName(
    groupNameList: List<GroupName>,
    groupId: number
): GroupName {
    return GetItem<GroupName>(groupNameList, groupId, gn => gn.GroupId);
}

//
//
//
export function GetSlices<T>(list: List<T>, sliceSize: number): List<List<T>> {
    const slices = new List<List<T>>();
    const elemCount = list.Count();
    const sliceCount = Math.ceil(elemCount / sliceSize);
    for (let i = 0; i < sliceCount; i++) {
        slices.Add(list.Skip(sliceSize * i).Take(sliceSize));
    }
    return slices;
}

//
// generic binary search algorithm
//
function GetItem<T>(
    list: List<T>,
    itemId: number,
    idSelector: (x: T) => number
): T {
    const arr = list.ToArray();
    let start = 0;
    let end = arr.length - 1;
    let mid = start;
    while (true) {
        if (start > end) {
            break;
        }

        mid = Math.floor((start + end) / 2);
        const item = arr[mid];
        const midId = idSelector(item);
        if (itemId === midId) {
            break;
        } else if (itemId < midId) {
            end = mid - 1;
        } else {
            start = mid + 1;
        }
    }
    return arr[mid];
}
